using System.Collections.Generic;
using System.ComponentModel;
using System.Resources;
using System.Reflection;
using System.CodeDom;

namespace ClassBuilderWizard.Interfaces
{
    public class DatabaseObject
    {
        private DatabaseObjectType _Type;
        private string _Name;
        private string _Schema;
        List<DatabaseColumn> _Columns;
        List<DatabaseColumn> _KeyColumns;
        private CodeTypeMemberCollection _EntityMembers;

        private string _EntityTemplate;
        private string _DataAccessTemplate;
        private string _ScriptTemplate;
        private string _EntityFieldTemplate;
        private string _EntityInitTemplate;
        private string _EntityPropertyTemplate;
        private string _EntityPropertyArrayComparer;
        private string _EntityPropertyNonArrayComparer;
        private string _DataAccessClassDefinition;
        private string _ScriptDefinition;

        private string _DeleteStoredProcedure;
        private string _SelectStoredProcedure;
        private string _SaveStoredProcedure;
        private string _SelectAllStoredProcedure;

        /// <summary>
        /// Create a new instance of DatabaseObject.
        /// </summary>
        /// <param name="language">The ProjectType (programming language) of the Visual Studio project</param>
        public DatabaseObject(ProjectType language)
        {
            this._Type = DatabaseObjectType.Table;
            this._Name = string.Empty;
            this._Schema = string.Empty;
            this._Columns = new List<DatabaseColumn>();
            this._KeyColumns = new List<DatabaseColumn>();

            ResourceManager rm = null;
            Assembly asm = Assembly.GetExecutingAssembly();
            switch (language)
            {
                case ProjectType.CSharp:
                    rm = new ResourceManager("ClassBuilderWizard.Interfaces.Templates_CS", asm);
                    break;
                case ProjectType.VB:
                    rm = new ResourceManager("ClassBuilderWizard.Interfaces.Templates_VB", asm);
                    break;
            }

            this._EntityTemplate = rm.GetString("Entity");
            this._DataAccessTemplate = rm.GetString("DataAccess");
            this._ScriptTemplate = rm.GetString("Script");

            this._EntityFieldTemplate = rm.GetString("Entity_Field_Template");
            this._EntityInitTemplate = rm.GetString("Entity_Init_Template");
            this._EntityPropertyTemplate = rm.GetString("Entity_Property_Template");
            this._EntityPropertyArrayComparer = rm.GetString("Entity_Property_Array_Comparer");
            this._EntityPropertyNonArrayComparer = rm.GetString("Entity_Property_NonArray_Comparer");

            this._DataAccessClassDefinition = string.Empty;

            this._EntityMembers = new CodeTypeMemberCollection();
        }
        /// <summary>
        /// Create a new instance of the DatabaseObject. The language used defaults to CSharp.
        /// </summary>
        public DatabaseObject() : this(ProjectType.CSharp)
        {
        }

        /// <summary>
        /// The template that will be used to generate the entity object
        /// </summary>
        /// <remarks>
        /// Several macros are used to indicate the placement of certain pieces of the entity class:
        /// [!output SAFE_NAMESPACE_NAME] - The namespace of the project
        /// [!output SAFE_CLASS_NAME] - The name of the class
        /// [!output PRIVATE_DEFINITIONS] - The definition of private fields
        /// [!output INITIALIZE_DEFINITIONS] - The initialization of private fields
        /// [!output PUBLIC_DEFINITIONS] - The definition of public properties
        /// </remarks>
        //[Browsable(false)]
        //public string EntityTemplate
        //{
        //    get { return this._EntityTemplate; }
        //    set { this._EntityTemplate = value; }
        //}
        /// <summary>
        /// The template that will be used to generate the data access class
        /// </summary>
        /// <remarks>
        /// Several macros are used to indicate the placement of certain pieces of the data access class:
        /// [!output SAFE_NAMESPACE_NAME] - The namespace of the project
        /// [!output SAFE_CLASS_NAME] - The name of the entity class
        /// [!output CLASS_DEFINITION] - The methods/functions that define the data access class
        /// </remarks>
        [Browsable(false)]
        public string DataAccessTemplate
        {
            get { return this._DataAccessTemplate; }
            set { this._DataAccessTemplate = value; }
        }
        /// <summary>
        /// The template that will be used to generate the scripts for the database
        /// </summary>
        /// <remarks>
        /// The macro that is used to indicate the placement of the database scripts:
        /// [!output SQL_SCRIPT] - The scripts for the database
        /// </remarks>
        [Browsable(false)]
        public string ScriptTemplate
        {
            get { return this._ScriptTemplate; }
            set { this._ScriptTemplate = value; }
        }

        /// <summary>
        /// The template that will be used to generate a field (private member) of the entity class
        /// </summary>
        /// <remarks>
        /// The macros used in this template are:
        /// [[Type]] - The CLR type of the field
        /// [[Name]] - The name of the field
        /// </remarks>
        //[Browsable(false)]
        //public string EntityFieldTemplate
        //{
        //    get { return this._EntityFieldTemplate; }
        //    set { this._EntityFieldTemplate = value; }
        //}
        /// <summary>
        /// The template that will be used to generate an line of code to initialize a field
        /// </summary>
        /// <remarks>
        /// The macros used in this template are:
        /// [[Name]] - The name of the field
        /// [[Default]] - The default value to assign to the field
        /// </remarks>
        //[Browsable(false)]
        //public string EntityInitTemplate
        //{
        //    get { return this._EntityInitTemplate; }
        //    set { this._EntityInitTemplate = value; }
        //}
        /// <summary>
        /// The template that will be used to generate a public property on the entity class
        /// </summary>
        /// <remarks>
        /// The macros used in this template are:
        /// [[Type]] - The CLR type of the property
        /// [[Name]] - The name of the property
        /// </remarks>
        //[Browsable(false)]
        //public string EntityPropertyTemplate
        //{
        //    get { return this._EntityPropertyTemplate; }
        //    set { this._EntityPropertyTemplate = value; }
        //}
        /// <summary>
        /// The comparison operator for array types
        /// </summary>
        //[Browsable(false)]
        //public string EntityPropertyArrayComparer
        //{
        //    get { return this._EntityPropertyArrayComparer; }
        //    set { this._EntityPropertyArrayComparer = value; }
        //}
        /// <summary>
        /// The comparison operator for non-array types
        /// </summary>
        //[Browsable(false)]
        //public string EntityPropertyNonArrayComparer
        //{
        //    get { return this._EntityPropertyNonArrayComparer; }
        //    set { this._EntityPropertyNonArrayComparer = value; }
        //}

        /// <summary>
        /// The data access class definition -- all of the methods and functions that make up the class
        /// </summary>
        /// <remarks>
        /// This property should be set by the plugin so that it can customize the code for the data access layer.
        /// </remarks>
        [Browsable(false)]
        public string DataAccessClassDefinition
        {
            get { return this._DataAccessClassDefinition; }
            set { this._DataAccessClassDefinition = value; }
        }

        /// <summary>
        /// The database script definition -- all stored procedures that are used by the data access class
        /// </summary>
        /// <remarks>
        /// This property should be set by the plugin so that it can customize the script for the database it was built for.
        /// </remarks>
        [Browsable(false)]
        public string ScriptDefinition
        {
            get { return this._ScriptDefinition; }
            set { this._ScriptDefinition = value; }
        }

        /// <summary>
        /// Plug-in defined entity class members (methods, properties, etc) to be included in the generated entity class
        /// </summary>
        [Browsable(false)]
        public CodeTypeMemberCollection EntityMembers
        {
            get { return this._EntityMembers; }
            set { this._EntityMembers = value; }
        }

        /// <summary>
        /// Which type of database object this object represents
        /// </summary>
        [Category("General")]
        [ReadOnly(true)]
        [DisplayName("Object Type")]
        public DatabaseObjectType Type
        {
            get { return this._Type; }
            set { this._Type = value; }
        }
        /// <summary>
        /// The name of the database object
        /// </summary>
        [Category("General")]
        [ReadOnly(true)]
        public string Name
        {
            get { return this._Name; }
            set { this._Name = value; }
        }
        /// <summary>
        /// The name of the schema the database object is a member of
        /// </summary>
        [Category("General")]
        [ReadOnly(true)]
        public string Schema
        {
            get { return this._Schema; }
            set { this._Schema = value; }
        }
        /// <summary>
        /// All columns in the database object
        /// </summary>
        [Description("All columns in the database object")]
        [Category("General")]
        [DisplayName("All Columns")]
        [ReadOnly(true)]
        public List<DatabaseColumn> Columns
        {
            get { return this._Columns; }
            set { this._Columns = value; }
        }
        /// <summary>
        /// One or more columns used as keys for the database object
        /// </summary>
        [Description("One or more columns to use as key fields")]
        [Category("General")]
        [DisplayName("Key Columns")]
        public List<DatabaseColumn> KeyColumns
        {
            get { return this._KeyColumns; }
            set { this._KeyColumns = value; }
        }
        /// <summary>
        /// Gets the number of columns in the database object
        /// </summary>
        [Category("General")]
        [ReadOnly(true)]
        public int ColumnCount
        {
            get { return this._Columns.Count; }
        }

        /// <summary>
        /// The name of the database command/stored procedure to call from the Data Access Layer to delete from the database
        /// </summary>
        [Description("Optional: The name of the Delete database command / stored procedure")]
        [Category("Database")]
        [DisplayName("Delete Command")]
        public string DeleteStoredProcedure
        {
            get
            {
                if (this._DeleteStoredProcedure == null)
                    this._DeleteStoredProcedure = string.Format("{0}_Delete", this.Name);
                return this._DeleteStoredProcedure;
            }
            set { this._DeleteStoredProcedure = value; }
        }

        /// <summary>
        /// The name of the database command/stored procedure to call from the Data Access Layer to select from the database
        /// </summary>
        [Description("Optional: The name of the Select database command / stored procedure")]
        [Category("Database")]
        [DisplayName("Select Command")]
        public string SelectStoredProcedure
        {
            get
            {
                if (this._SelectStoredProcedure == null)
                    this._SelectStoredProcedure = string.Format("{0}_Select", this.Name);
                return this._SelectStoredProcedure;
            }
            set { this._SelectStoredProcedure = value; }
        }

        /// <summary>
        /// The name of the database command/stored procedure to call from the Data Access Layer to save to the database
        /// </summary>
        [Description("Optional: The name of the Save database command / stored procedure")]
        [Category("Database")]
        [DisplayName("Save Command")]
        public string SaveStoredProcedure
        {
            get
            {
                if (this._SaveStoredProcedure == null)
                    this._SaveStoredProcedure = string.Format("{0}_Save", this.Name);
                return this._SaveStoredProcedure;
            }
            set { this._SaveStoredProcedure = value; }
        }
        /// <summary>
        /// The name of the database command/stored procedure to call from the Data Access Layer to select all items from the database
        /// </summary>
        [Description("Optional: The name of the Select All database command / stored procedure")]
        [Category("Database")]
        [DisplayName("Select All Command")]
        public string SelectAllStoredProcedure
        {
            get
            {
                if (this._SelectAllStoredProcedure == null)
                    this._SelectAllStoredProcedure = string.Format("{0}_SelectAll", this.Name);
                return this._SelectAllStoredProcedure;
            }
            set { this._SelectAllStoredProcedure = value; }
        }
    }
}
